package com.asen.commons.core.jdbc.handler;

import com.fasterxml.jackson.databind.util.StdDateFormat;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.sql.*;
import java.util.Collection;
import java.util.Date;

/**
 * Date 类型处理器
 *
 * @author Gary
 * @version 1.0
 * @date 2018-12-02
 */
public class DateTypeHandler extends BaseTypeHandler<Date> {

    private final static String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";

    public final static String[] ALL_FORMATS = new String[]{
            "yyyy-MM-dd HH:mm:ss.SSS",
            "yyyy-MM-dd HH:mm:ss",
            "yyyy-MM-dd'T'HH:mm:ss",
            "yyyy-MM-dd'T'HH:mm",
            "yyyy-MM-dd HH:mm",
            "yyyy-MM-dd HH:mm",
            "yyyy-MM-dd",
            "yyyy/MM/dd HH:mm:ss.SSS",
            "yyyy/MM/dd HH:mm:ss",
            "yyyy/MM/dd HH:mm",
            "yyyy/MM/dd HH:mm",
            "yyyy/MM/dd",
            "yyyyMMdd HH:mm:ss.SSS",
            "yyyyMMdd HH:mm:ss",
            "yyyyMMdd HH:mm",
            "yyyyMMdd HH:mm",
            "yyyyMMdd"
    };

    @Override
    public int getSqlType() {
        return Types.TIMESTAMP;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Date parameter)
            throws SQLException {
        ps.setTimestamp(i, new Timestamp((parameter).getTime()));
    }

    @Override
    public Date getNullableResult(ResultSet rs, String columnName)
            throws SQLException {
        Timestamp sqlTimestamp = rs.getTimestamp(columnName);
        if (sqlTimestamp != null) {
            return new Date(sqlTimestamp.getTime());
        }
        return null;
    }

    @Override
    public Date getNullableResult(ResultSet rs, int columnIndex)
            throws SQLException {
        Timestamp sqlTimestamp = rs.getTimestamp(columnIndex);
        if (sqlTimestamp != null) {
            return new Date(sqlTimestamp.getTime());
        }
        return null;
    }

    @Override
    public Date getNullableResult(CallableStatement cs, int columnIndex)
            throws SQLException {
        Timestamp sqlTimestamp = cs.getTimestamp(columnIndex);
        if (sqlTimestamp != null) {
            return new Date(sqlTimestamp.getTime());
        }
        return null;
    }

    @Override
    public String toSqlValue(Object value) {
        if (value == null) {
            return null;
        }

        if (value instanceof Date) {
            String strTime = DateFormatUtils.format((Date) value, DEFAULT_FORMAT);
            return "\'" + strTime + "\'";
        }

        if (value instanceof String) {
            return "\'" + value.toString() + "\'";
        }

        if (value instanceof Date[]) {
            StringBuilder sb = new StringBuilder(0);
            sb.append("(");
            for (Date s : (Date[]) value) {
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                String strTime = DateFormatUtils.format((Date) value, DEFAULT_FORMAT);
                sb.append("\'" + strTime + "\'");
            }
            sb.append(")");
            return sb.toString();
        }

        if (value instanceof String[]) {
            return getSqlValue((String[]) value, true);
        }

        if (value instanceof Collection) {
            Collection collection = (Collection) value;
            StringBuilder sb = new StringBuilder(0);
            for (Object obj : collection) {
                if (obj == null) {
                    continue;
                }

                if (sb.length() > 0) {
                    sb.append(", ");
                }

                String s = obj.toString();
                if (obj instanceof Date) {
                    s = DateFormatUtils.format((Date) obj, DEFAULT_FORMAT);
                }

                sb.append("\'" + s + "\'");
            }
            if (sb.length() > 0) {
                sb.insert(0, "(");
                sb.append(")");
            }
            return sb.toString();
        }

        return "\'" + value.toString() + "\'";
    }

    @Override
    public Date getValue(Object value) throws Exception {
        if (value == null) {
            return null;
        }

        if (Date.class.isAssignableFrom(value.getClass())) {
            return (Date) value;
        }

        String sDate = value.toString();

        // 格式：2021-08-27T00:00:00.000+08:00
        if (sDate.contains("T") && sDate.contains("+")) {
            return new StdDateFormat().parse(sDate);
        } else {
            return DateUtils.parseDate(sDate, ALL_FORMATS);
        }
    }
}
